/**
 * This file is part of the CAKIS project.
 * 
 * Copyright (c) 2009-2010 - Florian Arndt, Christian Kerl
 * 
 * @license GNU Lesser General Public License v3 <http://www.opensource.org/licenses/lgpl-3.0.html>
 * @since   01.03.2010
 * @version SVN: $Id: CakisClientServiceRemoteImpl.java 144 2010-05-15 12:02:22Z christian-kerl@web.de $
 */

package org.cakis.server.service.impl;

import java.util.ArrayList;
import java.util.List;

import javax.ejb.Stateless;
import javax.interceptor.ExcludeClassInterceptors;
import javax.interceptor.Interceptors;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;

import org.cakis.server.Names;
import org.cakis.server.model.Product;
import org.cakis.server.model.ProductList;
import org.cakis.server.model.StockUnit;
import org.cakis.server.service.ProductListService;
import org.cakis.server.service.ProductNotFoundException;
import org.cakis.server.service.ProductService;
import org.cakis.server.service.RecipeService;
import org.cakis.server.service.StockService;
import org.cakis.server.service.StockUnitNotFoundException;
import org.cakis.server.service.session.ClientAwareService;
import org.cakis.server.service.session.ClientSession;
import org.cakis.server.service.session.ClientSessionAccessInterceptor;
import org.jboss.seam.Component;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;

@Name(Names.CakisClientService)
@Scope(ScopeType.STATELESS)
@Stateless(name = Names.CakisClientService)
@Interceptors(ClientSessionAccessInterceptor.class)
@WebService(name = Names.CakisClientService, serviceName = Names.CakisClientService)
public class CakisClientServiceRemoteImpl implements ClientAwareService.Remote, ProductService.Remote, ProductListService.Remote, RecipeService.Remote, StockService.Remote {
    private ProductService productService;
    private ProductListService productListService;
    private RecipeService.Remote recipeService;
    private StockService stockService;

    @In(Names.ProductService)
    public void setProductService(ProductService productService) {
        this.productService = productService;
    }

    @In(Names.ProductListService)
    public void setProductListService(ProductListService productListService) {
        this.productListService = productListService;
    }

    @In(Names.RecipeServiceRemote)
    public void setRecipeService(RecipeService.Remote recipeService) {
        this.recipeService = recipeService;
    }

    @In(Names.StockService)
    public void setStockService(StockService stockService) {
        this.stockService = stockService;
    }

    @WebMethod
    @ExcludeClassInterceptors
    @Override
    public void beginClientSession(
            @WebParam(name = "clientId") String clientId
    ) {
        ClientSession session = getClientSession(true);
        session.init(clientId);
    }

    @WebMethod
    @ExcludeClassInterceptors
    @Override
    public void endClientSession() {
        ClientSession session = getClientSession(false);

        if(session != null) {
            session.destroy();
        }
    }

    @WebMethod
    @Override
    public void openRecipeInServerSession(
            @WebParam(name = "uuid") String uuid
    ) {
        recipeService.openRecipeInServerSession(uuid);
    }

    @WebMethod
    @Override
    public List<StockUnit> getAllStockUnits() {
        return productService.getAllStockUnits();
    }

    // FIXME: method overloading in webservice not possible
    //@WebMethod(operationName="getProductById")
    @Override
    public Product getProduct(
            /* @WebParam(name = "productId") */ Long id
    ) throws ProductNotFoundException {
        return productService.getProduct(id);
    }

    @WebMethod
    @Override
    public Product getProduct(
            @WebParam(name = "ean") String ean
    ) throws ProductNotFoundException, StockUnitNotFoundException {
        Product result = productService.getProduct(ean);

        // transparently stores a product retrieved from external datasource
        // TODO: handle in ProductServiceImpl
        if(result.getId() == null) {
            result = productService.addProduct(result);
        }

        return result;
    }

    @WebMethod
    @Override
    public Product addProduct(
            @WebParam(name = "product") Product product
    ) throws IllegalArgumentException, StockUnitNotFoundException {
        return productService.addProduct(product);
    }

    @WebMethod
    @Override
    public boolean addStockItem(
            @WebParam(name = "productId") Long productId,
            @WebParam(name = "count") int count
    ) throws ProductNotFoundException {
        return stockService.addStockItem(productId, count);
    }


    @WebMethod
    @Override
    public int deleteStockItem(
            @WebParam(name = "productId") Long productId,
            @WebParam(name = "count") int count
    ) throws ProductNotFoundException {
        return stockService.deleteStockItem(productId, count);
    }

    @WebMethod
    @Override
    public List<ProductList> getProductLists() {
        List<ProductList> internal = productListService.getProductLists();
        List<ProductList> result = new ArrayList<ProductList>(internal.size());

        // create from EntityManager detached copy
        for(ProductList list : internal) {
            ProductList resultList = new ProductList();
            resultList.setId(list.getId());
            resultList.setName(list.getName());
            resultList.setIsArchived(list.getIsArchived());

            result.add(resultList);
        }

        return result;
    }

    @WebMethod
    @Override
    public ProductList getProductListWithContent(
            @WebParam(name = "productListId") Long productListId
    ) {
        return productListService.getProductListWithContent(productListId);
    }

    private ClientSession getClientSession(boolean create) {
        return (ClientSession)Component.getInstance(ClientSession.class, create);
    }
}
